package com.thingple.reader;

import android.content.Context;
import android.hardware.usb.UsbAccessory;
import android.util.Log;

import com.thingple.rodbell.PacketProcessor;
import com.thingple.rodbell.listener.CarryStateListener;
import com.thingple.rodbell.listener.TagListener;
import com.thingple.rodbell.packet.PacketProcessorImpl;
import com.thingple.usb.manager.DeviceListener;
import com.thingple.usb.manager.UsbDeviceManager;
import com.thingple.usb.manager.UsbManagerWrapper;
import com.thingple.usb.session.UsbSession;

import org.jetbrains.annotations.NotNull;

public class UsbReader {

    private static final String TAG = UsbReader.class.getName();

    private static final int baudRate = 115200;

    private Context ctx;

    private UsbSession session;

    private PacketProcessor packetProcessor;

    private final ReaderListener listener;

    private TagListener tagListener;
    private CarryStateListener carryStateListener;

    public UsbReader setTagListener(TagListener listener) {
        tagListener = listener;
        return this;
    }

    public UsbReader setCarryStateListener(CarryStateListener listener) {
        carryStateListener = listener;
        return this;
    }

    public interface ReaderListener {
        void onConnected(UsbSession session, Exception err);
    }

    public UsbReader(Context ctx, ReaderListener listener) {
        this.ctx = ctx;
        this.listener = listener;

    }

    public void connect() {
        initPacketProcessor();
        connectReader();
    }
    public void close() {
        if (packetProcessor != null) {
            packetProcessor.stop();
            packetProcessor = null;
        }
        if (session != null) {
            session.stop();
            session.destroy();
            session = null;
        }
    }

    private void initPacketProcessor() {
        packetProcessor = new PacketProcessorImpl();
        packetProcessor.setDebug(true);
        packetProcessor.start();
        packetProcessor.setTagListener(tagInfo -> {
            if (tagListener != null) {
                tagListener.onTag(tagInfo);
            }
        });
        packetProcessor.setCarryStateListener(state -> {
            if (carryStateListener != null) {
                carryStateListener.onStateChange(state);
            }
        });
    }

    private void connectReader() {
        UsbDeviceManager receiver = UsbManagerWrapper.getDeviceManager();
        receiver.setListener(new DeviceListener() {

            @Override
            public void onDeviceAttach(UsbAccessory device) {
                Log.d(TAG, "attach device:" + device.getModel());
            }

            @Override
            public void onDeviceDetach(UsbAccessory device) {
                Log.d(TAG, "detach:" + device.getModel());
            }

            @Override
            public void onDeviceAllowed(UsbAccessory device) {
                Log.d(TAG, "allowed device:" + device.getModel());
                session = createSession(device);
                if (session == null) {
                    onSessionCreateFail();// 无session
                    return;
                }
                onSessionCreate(); // 有session
                initSession(session);
            }
        });
        receiver.registerSpec("Thingple");
        receiver.startMonitor();
        Log.i(TAG, "scan usb device...");
        receiver.scan(); // 扫描已经插入的设备
    }

    private UsbSession createSession(@NotNull UsbAccessory device) {
        UsbSession session = UsbManagerWrapper.getDeviceManager().createSession(device, baudRate);
        if (session == null) {
            Log.d(TAG, "创建Usb session失败");
            return null;
        }

        return session;
    }

    private void initSession(UsbSession session) {
        session.setStreamUpListener((data, n) -> {
            packetProcessor.onReceiveData(data);
        });
        session.setAutoResetRework(true);
        session.setReworkEnable(true);

        session.start();
    }

    private void onSessionCreate() {
        if (listener != null) {
            listener.onConnected(session, null);
        }
    }
    private void onSessionCreateFail() {
        if (listener != null) {
            listener.onConnected(session, new Exception("create fail"));
        }
    }
}
